package xin.mydreams.mybill.widget.home.service.impl;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
import xin.mydreams.mybill.global.result.exception.MessageException;
import xin.mydreams.mybill.util.CodeUtil;
import xin.mydreams.mybill.widget.home.service.ILoginService;
import xin.mydreams.mybill.widget.user.entity.User;
import xin.mydreams.mybill.widget.user.service.IUserService;

/**
 * 
 * @Type LoginServiceImpl.java
 * @author 谷泽昊
 * @date 2018年8月9日 下午6:33:05
 * @version
 */
@Slf4j
@Service
public class LoginServiceImpl implements ILoginService {

	@Autowired
	private IUserService userService;

	@Override
	public User login(UsernamePasswordToken token, String userName, String ip) throws MessageException {
		// 调用接口获取access_token
		log.error("用户[" + userName + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
		Subject currentUser = SecurityUtils.getSubject();
		try {
			// 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
			// 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
			// 所以这一步在调用login(token)方法时,它会走到MyShiroRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
			log.error("对用户[" + userName + "]进行登录验证..验证开始");
			currentUser.login(token);
		} catch (UnknownAccountException uae) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,未知账户");
			throw new MessageException(CodeUtil.FAIL, "账号或密码错误！");
		} catch (IncorrectCredentialsException ice) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,错误的凭证");
			throw new MessageException(CodeUtil.FAIL, "账号或密码错误！", ice);
		} catch (LockedAccountException lae) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,账户已锁定");
			throw new MessageException(CodeUtil.FAIL, "[" + userName + "]账户已锁定！", lae);
		} catch (ExcessiveAttemptsException eae) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,错误次数大于5次,账户已锁定");
			throw new MessageException(CodeUtil.FAIL, "[" + userName + "]错误次数大于5次，账户已锁定！", eae);
		} catch (DisabledAccountException sae) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,帐号已经禁止登录");
			throw new MessageException(CodeUtil.FAIL, "[" + userName + "]账号已经禁用！", sae);
		} catch (ExpiredCredentialsException ee) {
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,帐号已经过期");
			throw new MessageException(CodeUtil.FAIL, "[" + userName + "]机构或账号已经过期！", ee);
		} catch (AuthenticationException ae) {
			// 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
			log.error("对用户[" + userName + "]进行登录验证..验证未通过,堆栈轨迹如下:" + ae);
			throw new MessageException(CodeUtil.FAIL, "[" + userName + "]未知错误！", ae);

		}
		// 验证是否登录成功
		if (currentUser.isAuthenticated()) {
			log.error("用户[" + userName + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
			User user = userService.findByUserName(userName);
			// 登录成功，更改ip和时间
			user.setLastLoginIp(ip);
			try {
				userService.save(user);

			} catch (Exception e) {
				log.error("修改失败!", e);
				currentUser.logout();
				throw new MessageException(CodeUtil.FAIL, "[" + userName + "]未知错误！", e);
			}
			return user;
		} else {
			token.clear();
		}
		throw new MessageException(CodeUtil.FAIL, "[" + userName + "]未知错误！");
	}

}

/**
 *
 * Revision history
 * -------------------------------------------------------------------------
 * 
 * Date Author Note
 * -------------------------------------------------------------------------
 * 2018年8月9日 谷泽昊 creat
 */